#include "KeyEvent.h"



//#0 ****************************   宏定义   ****************************************************************
#define NONE_VALUE                  0x00    /* 无键值 */
#define INVALID_VALUE               0xFF    /* 无效键值 */
#define COMBINATION_RELEASE_VALUE   0xFE    /* 等待组合键释放键值 */



//#0 ****************************   变量定义   **************************************************************
/* 短按按键 */
#if KEY_MAX_SHORT
static ShortKey_T SYS_RAM stShortKey[KEY_MAX_SHORT];
#endif

/* 长短按键 */
#if KEY_MAX_LONG
static LongKey_T SYS_RAM stLongKey[KEY_MAX_LONG];
#endif



//#1 ****************************   初始化   ****************************************************************
/************************************************************************************************************
 * @功能:    初始化
 * @参数:    无
 * @返回:    无
************************************************************************************************************/
void KeyEvent_Init(void)
{
#if KEY_MAX_SHORT
    memset(&stShortKey, 0, sizeof(stShortKey));
#endif

#if KEY_MAX_LONG
    memset(&stLongKey, 0, sizeof(stLongKey));
#endif
}

/************************************************************************************************************
 * @功能:    短按按键注册
 * @参数:    event_cb: 回调函数
 * @参数:    key_val:  按键键值
 * @返回:    短按按键句柄
************************************************************************************************************/
#if KEY_MAX_SHORT
ShortKey_T *KeyEvent_CreateShort(void (*event_cb)(KeyEvent_E), uint8_t key_val)
{
    uint8_t i = 0;

    /* 创建短按按键 */
    for (i = 0; i < KEY_MAX_SHORT; i++)
    {
        if (!stShortKey[i].b1Create)
        {
            stShortKey[i].b1Create    = 1;
            stShortKey[i].u8key_value = key_val;
            stShortKey[i].event_cb    = event_cb;
            return &stShortKey[i];
        }
    }

    /* 创建失败 */
    return NULL;
}
#endif

/************************************************************************************************************
 * @功能:    长短按键注册
 * @参数:    event_cb:   回调函数
 * @参数:    key_val:    按键键值
 * @参数:    long_start: 长按开始时间(单位: ms)
 * @参数:    long_hold:  长按保持时间(单位: ms)
 * @返回:    长短按键句柄
************************************************************************************************************/
#if KEY_MAX_LONG
LongKey_T *KeyEvent_CreateLong(void (*event_cb)(KeyEvent_E), uint8_t key_val, uint16_t long_start, uint16_t long_hold)
{
    uint8_t i = 0;

    /* ms单位 转成 tick单位 */
    long_start /= KEY_TICK_TIME;
    long_hold  /= KEY_TICK_TIME;
    if (long_hold == 0)
    {
        long_hold = 220;
    }

    /* 创建长短按键 */
    for (i = 0; i < KEY_MAX_LONG; i++)
    {
        if (!stLongKey[i].b1Create)
        {
            stLongKey[i].b1Create = 1;

            stLongKey[i].u8long_hold_time   = long_hold;    /* 长按保持时间 */
            stLongKey[i].u16long_start_time = long_start;   /* 长按开始时间 */
            stLongKey[i].u16comparison_time = long_start;   /* 按下比较时间 */

            stLongKey[i].u8key_value = key_val;             /* 按键键值 */
            stLongKey[i].event_cb    = event_cb;            /* 按键事件处理函数 */
            return &stLongKey[i];                           /* 返回按键句柄 */
        }
    }

    /* 创建失败 */
    return NULL;
}
#endif



//#2 ****************************   按键扫描   **************************************************************
/************************************************************************************************************
 * @功能:    短按按键扫描
 * @参数:    key_val: 按键键值
 * @返回:    无
************************************************************************************************************/
#if KEY_MAX_SHORT
static void KeyEvent_ShortTick(uint8_t key_val)
{
    static uint8_t i = 0;
    static ShortKey_T SYS_RAM *Key = NULL;

    for (i = 0; i < KEY_MAX_SHORT; i++)
    {
        Key = &stShortKey[i];
        if (Key->b1Create)
        {
            /* 获取新的按键状态 */
            if (Key->u8key_value == key_val)
            {
                Key->b1new_key = 1;
            }
            else if (key_val == NONE_VALUE)
            {
                Key->b1new_key = 0;
            }
            else
            {
                if (key_val == COMBINATION_RELEASE_VALUE)
                {
                    continue;
                }
                else
                {
                    Key->b1new_key = 0;
                    Key->b1old_key = 0;
                }
            }

            /* 按下/松开判断 */
            if (Key->b1old_key != Key->b1new_key)
            {
                Key->b1old_key = Key->b1new_key;

                /* 执行回调函数 */
                if (Key->b1new_key)
                {
                    Key->event_cb(KEY_EVENT_DOWN);
                }
                else
                {
                    Key->event_cb(KEY_EVENT_UP);
                }
            }
        }
    }
}
#endif

/************************************************************************************************************
 * @功能:    长按按键扫描
 * @参数:    key_val: 按键键值
 * @返回:    无
************************************************************************************************************/
#if KEY_MAX_LONG
static void KeyEvent_LongTick(uint8_t key_val)
{
    static uint8_t i = 0;
    static LongKey_T SYS_RAM *Key = NULL;

    for (i = 0; i < KEY_MAX_LONG; i++)
    {
        Key = &stLongKey[i];
        if (Key->b1Create)
        {
            /* 获取新的按键状态 */
            if (Key->u8key_value == key_val)
            {
                Key->b1new_key = 1;
            }
            else if (key_val == NONE_VALUE)
            {
                Key->b1new_key = 0;
            }
            else
            {
                if (key_val == COMBINATION_RELEASE_VALUE)
                {
                    continue;
                }
                else
                {
                    Key->b1new_key = 0;
                    Key->b1old_key = 0;
                }
            }

            /* 按下/松开判断 */
            if (Key->b1old_key != Key->b1new_key)
            {
                Key->b1old_key = Key->b1new_key;

                /* 执行回调函数 */
                if (Key->b1new_key)
                {
                    Key->event_cb(KEY_EVENT_DOWN);
                }
                else if (!Key->b1long_start_flag)
                {
                    Key->event_cb(KEY_EVENT_UP);
                }
                else
                {
                    Key->event_cb(KEY_EVENT_LONG_UP);
                }
            }

            /* 长按开始/长按保持判断 */
            if (Key->b1new_key)
            {
                Key->u16hold_time++;
                if (Key->u16hold_time >= Key->u16comparison_time)
                {
                    Key->b1long_start_flag = 1;

                    /* 长按开始回调 */
                    if (Key->u16hold_time == Key->u16long_start_time)
                    {
                        Key->event_cb(KEY_EVENT_LONG_START);
                    }
                    /* 长按保持回调 */
                    else
                    {
                        Key->event_cb(KEY_EVENT_LONG_HOLD);
                    }

                    /* 小于代表已经溢出,溢出处理 */
                    Key->u16comparison_time += Key->u8long_hold_time;
                    if (Key->u16comparison_time < Key->u16hold_time)
                    {
                        Key->u16comparison_time = Key->u16long_start_time + Key->u8long_hold_time;
                        Key->u16hold_time       = Key->u16long_start_time;
                    }
                }
            }
            else
            {
                Key->u16comparison_time = Key->u16long_start_time;  /* 恢复长按开始比较时间 */
                Key->u16hold_time       = 0;                        /* 复位保持计数 */
                Key->b1long_start_flag  = 0;                        /* 复位长按开始标记 */
            }
        }
    }
}
#endif

/************************************************************************************************************
 * @功能:    按键扫描
 * @参数:    key_val: 按键键值
 * @返回:    无
************************************************************************************************************/
void KeyEvent_Tick(uint8_t key_val)
{
#if KEY_MAX_SHORT
    KeyEvent_ShortTick(key_val);
#endif

#if KEY_MAX_LONG
    KeyEvent_LongTick(key_val);
#endif
}
